/**
 * Author: Wang Haitao
 * Date: 2024-xx-xx
 * Description: 这个文件关于INA228的大部分驱动实现
 * Code Copy：拷贝代码，请加上作者信息。
 */
#include "ina22x_driver.h"
#include <stdio.h>

#define     INA226_VBus_LSB		    1.25f                        //总线电压mV
#define 	INA226_Shunt_LSB    	2.5f	                     //分流电压uV
#define     INA226_Current_LSB      (INA22x_Max_Current_mA/32768)//电流mA
#define     INA226_Power_LSB        (25*INA226_Current_LSB)      //功率mW

typedef enum
{
    INA226_Config        = 0x00, //配置命令
 	INA226_Shunt_Voltage = 0x01, //分流电压
 	INA226_Bus_Voltage   = 0x02, //总线电压
 	INA226_Power 		 = 0x03, //电源功率
 	INA226_Current 	     = 0x04, //电流
 	INA226_Calibration   = 0x05, //校准
 	INA226_Mask_Enable   = 0x06, //屏蔽 使能 警报配置和转换准备就绪      
 	INA226_Alert_Limit   = 0x07, //警报比较的限定值     
}WHT_INA226_Cmd_enum;


/**********************驱动初始化配置*********************/
static SemaphoreHandle_t Tx_xSemaphore;//二值信号量句柄
static SemaphoreHandle_t Rx_xSemaphore;
static WHT_I2C_Cache_t WHT_Cache;
static void WHT_Tx_Idle_IT_Callback(void);
static void WHT_Rx_Idle_IT_Callback(void);
static void WHT_I2C_BUS_Init(void)
{
    if (WHT_I2C_BUS1_Init() != 0)
    {
        /* 总线初始化失败 */
        printf("INA226:I2C BUS Init ERROR\r\n");
        return;
    }
    WHT_Cache.Cmd_Count = 1;
    WHT_Cache.Read_Finish_IT_CB = WHT_Rx_Idle_IT_Callback;
    WHT_Cache.Write_Finish_IT_CB = WHT_Tx_Idle_IT_Callback;

    Tx_xSemaphore = xSemaphoreCreateBinary();
    Rx_xSemaphore = xSemaphoreCreateBinary();
}
/**********************驱动初始化配置*********************/

/************************** read & write *******************************/
/*发送空闲中断回调函数*/
static void WHT_Tx_Idle_IT_Callback(void)
{
    BaseType_t xHigherPriorityTaskWoken;

    xSemaphoreGiveFromISR(Tx_xSemaphore, &xHigherPriorityTaskWoken);
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
/*接收空闲中断回调函数*/
static void WHT_Rx_Idle_IT_Callback(void)
{
    BaseType_t xHigherPriorityTaskWoken;

    xSemaphoreGiveFromISR(Rx_xSemaphore, &xHigherPriorityTaskWoken);
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
static void WHT_I2C_Write(uint8_t addr_7bit, WHT_INA226_Cmd_enum cmd, uint8_t* const input_buf, uint32_t count)
{
    while (WHT_I2C_BUS1->Mutex == I2C_Lock)
        vTaskDelay(1);
    WHT_Cache.Addr_7Bit = addr_7bit;
    WHT_Cache.Dir = I2C_Write;
    WHT_Cache.Cmd[0] = cmd;
    WHT_Cache.Buffer = input_buf;
    WHT_Cache.Buffer_Count = count;

    TickType_t Tick_Count = count * 9 * 1000  / WHT_I2C_BUS1->Config.I2C_Rate_Hz / portTICK_RATE_MS;//单位ms/Tick
    if (Tick_Count)
        WHT_I2C_BUS_OPS.Read_Write_DMA(WHT_I2C_BUS1, &WHT_Cache);
    else
        WHT_I2C_BUS_OPS.Read_Write_IT(WHT_I2C_BUS1, &WHT_Cache);
    
    if (WHT_I2C_BUS1->Mutex == I2C_Unlock)//传输结束
    {
        /*用户可以加入判断是否有错误相关代码*/
    }
    else
        xSemaphoreTake(Tx_xSemaphore, portMAX_DELAY);//等待信号量
}
static void WHT_I2C_Read(uint8_t addr_7bit, WHT_INA226_Cmd_enum cmd, uint8_t* const output_buf, uint32_t count)
{
    while (WHT_I2C_BUS1->Mutex == I2C_Lock)//等待互斥锁成功打开
        vTaskDelay(1);
    WHT_Cache.Addr_7Bit = addr_7bit;
    WHT_Cache.Dir = I2C_Read;
    WHT_Cache.Cmd[0] = cmd;
    WHT_Cache.Buffer = output_buf;
    WHT_Cache.Buffer_Count = count;

    TickType_t Tick_Count = count * 9 * 1000  / WHT_I2C_BUS1->Config.I2C_Rate_Hz / portTICK_RATE_MS;//单位ms/Tick
    if (Tick_Count)
        WHT_I2C_BUS_OPS.Read_Write_DMA(WHT_I2C_BUS1, &WHT_Cache);
    else
        WHT_I2C_BUS_OPS.Read_Write_IT(WHT_I2C_BUS1, &WHT_Cache);
    
    if (WHT_I2C_BUS1->Mutex == I2C_Unlock)//传输结束
    {
        /*用户可以加入判断是否有错误相关代码*/
    }
    else
        xSemaphoreTake(Rx_xSemaphore, portMAX_DELAY);//等待信号量
}
static uint8_t WHT_INA226_Scan_I2C_Slave_Count(void)
{
    return WHT_I2C_BUS_OPS.Scan_Mount_Count(WHT_I2C_BUS1);
}
/************************** read & write *******************************/


static uint8_t TRx_Buffer[4];

/* 分流电压 */
static void WHT_INA226_Get_Shunt_Voltage(WHT_INA226_Info_t* info)
{
    int16_t Temp;

    WHT_I2C_Read(info->Config.Addr, INA226_Shunt_Voltage, TRx_Buffer, 2);
    Temp = TRx_Buffer[0] << 8 | TRx_Buffer[1];
    info->Result->Shunt_Voltage_uV = Temp * INA226_Shunt_LSB;
}
/* 总线电压 */
static void WHT_INA226_Get_VBus_Voltage(WHT_INA226_Info_t* info)
{
    uint16_t Temp;
    
    WHT_I2C_Read(info->Config.Addr, INA226_Bus_Voltage, TRx_Buffer, 2);
    Temp = (TRx_Buffer[0]<<8) | TRx_Buffer[1];
    info->Result->Voltage_mV =Temp * INA226_VBus_LSB * info->Config.Calibration_VBus_Gain_Val;
}
/* 总线电流 */
static void WHT_INA226_Get_IBus_Current(WHT_INA226_Info_t* info)
{
    int16_t Temp;

    WHT_I2C_Read(info->Config.Addr, INA226_Current, TRx_Buffer, 2);
    Temp = (TRx_Buffer[0]<<8) | TRx_Buffer[1];
    info->Result->Current_mA = Temp * INA226_Current_LSB;
}
/* 总线功率 */
static void WHT_INA226_Get_WBus_Power(WHT_INA226_Info_t* info)
{
    uint16_t Temp;

    WHT_I2C_Read(info->Config.Addr, INA226_Power, TRx_Buffer, 2);
    Temp = (TRx_Buffer[0]<<8) | TRx_Buffer[1];
    info->Result->Power_mW = Temp * INA226_Power_LSB;
}
/* 获取电流默认校准值 */
static uint16_t WHT_INA226_Get_Default_CAL(WHT_INA226_Info_t* info)
{
    return (uint16_t)(5120/INA226_Current_LSB/info->Config.Sampling_Res_Milliohm);
}
/* 设置电流校准值 */
static void WHT_INA226_Set_CAL(WHT_INA226_Info_t* info)
{
    TRx_Buffer[0] = info->Config.Calibration_Shunt_Gain_Val >> 8;
    TRx_Buffer[1] = info->Config.Calibration_Shunt_Gain_Val & 0xff;
    WHT_I2C_Write(info->Config.Addr, INA226_Calibration, TRx_Buffer, 2);//设置电流分辨率
}
/* 设置采样转换时间 */
static void WHT_INA226_Set_CNV_Time(WHT_INA226_Info_t* info)
{
    uint16_t Temp;

    WHT_I2C_Read(info->Config.Addr, INA226_Config, TRx_Buffer, 2);
    Temp = (TRx_Buffer[0]<<8) | TRx_Buffer[1];
    Temp &= 0xf007;
    switch (info->Config.Convert_Time)
    {
    case CNV_Time_5ms: Temp |= (1<<9) | (3<<6) | (3<<3);break;
    case CNV_Time_9ms: Temp |= (1<<9) | (4<<6) | (4<<3);break;
    case CNV_Time_17ms:Temp |= (1<<9) | (5<<6) | (5<<3);break;
    case CNV_Time_19ms:Temp |= (2<<9) | (3<<6) | (3<<3);break;
    default:
        return;
    }
    TRx_Buffer[0] = Temp >> 8;
    TRx_Buffer[1] = Temp & 0xff;
    WHT_I2C_Write(info->Config.Addr, INA226_Config, TRx_Buffer, 2);
}
/* 设置工作模式 */
static void WHT_INA226_Set_Work_Mode(WHT_INA226_Info_t* info)
{
    WHT_I2C_Read(info->Config.Addr, INA226_Config, TRx_Buffer, 2);
    TRx_Buffer[1] &= ~7;
    TRx_Buffer[1] |= info->Config.Mode;
    WHT_I2C_Write(info->Config.Addr, INA226_Config, TRx_Buffer, 2);
}
/* 设置报警功能 */
static void WHT_INA226_Set_Alert_Func(WHT_INA226_Info_t* info)
{
    uint16_t Temp;

    Temp = 0;
    Temp |= info->Config.Alert_SHNTOL << 15;
    Temp |= info->Config.Alert_SHNTUL << 14;
    Temp |= info->Config.Alert_BUSOL << 13;
    Temp |= info->Config.Alert_BUSUL << 12;
    Temp |= info->Config.Alert_POL << 11;
    Temp |= info->Config.Alert_CNVR << 10;
    Temp |= info->Config.Alert_APOL << 1;
    Temp |= info->Config.Alert_ALATCH << 0;
    TRx_Buffer[0] = Temp >> 8;
    TRx_Buffer[1] = Temp & 0xff;
    WHT_I2C_Write(info->Config.Addr, INA226_Mask_Enable, TRx_Buffer, 2);
}
/* 获取报警标志 */
static uint16_t WHT_INA226_Get_Alert_Flag(WHT_INA226_Info_t* info)
{
    WHT_I2C_Read(info->Config.Addr, INA226_Mask_Enable, TRx_Buffer, 2);
    return TRx_Buffer[0] << 8 | TRx_Buffer[1];

}
/* 设置报警值 */
static void WHT_INA226_Set_Alert_Value(WHT_INA226_Info_t* info)
{
    uint16_t Temp;

    if (info->Config.Alert_SHNTOL == ENABLE)
        Temp = info->Config.Alert_Current_Hig;
    else if (info->Config.Alert_SHNTUL == ENABLE)
        Temp = info->Config.Alert_Current_Low;
    else if (info->Config.Alert_BUSOL == ENABLE)
        Temp = info->Config.Alert_Voltage_Hig;
    else if (info->Config.Alert_BUSUL == ENABLE)
        Temp = info->Config.Alert_Voltage_Low;
    else if (info->Config.Alert_POL == ENABLE)
        Temp = info->Config.Alert_Power_Hig;
    else
        return;
    
    TRx_Buffer[0] = Temp >> 8;
    TRx_Buffer[1] = Temp & 0xff;
    WHT_I2C_Write(info->Config.Addr, INA226_Alert_Limit, TRx_Buffer, 2);
}
/* 初始化采集芯片 */
static void WHT_INA226_Init(WHT_INA226_Info_t* info)
{
    static FlagStatus I2C_BUS_Init_Flag = RESET;

    if (I2C_BUS_Init_Flag == RESET)
    {
        I2C_BUS_Init_Flag = SET;
        WHT_I2C_BUS_Init();
        WHT_INA22x_Alert_Status.WHT_Init();
    }

    TRx_Buffer[0] |= SET<<7;
    WHT_I2C_Write(info->Config.Addr, INA226_Config, TRx_Buffer, 2);//重新启动

    vTaskDelay(20);
    WHT_INA226_Driver.WHT_Set_Calibration_Shunt_Gain(info);
    WHT_INA226_Driver.WHT_Set_Convert_Time(info);
    WHT_INA226_Driver.WHT_Set_Alert_Value(info);
    WHT_INA226_Driver.WHT_Set_Alert_Func(info);
    WHT_INA226_Driver.WHT_Set_Work_Mode(info);
}

const WHT_INA226_Driver_t WHT_INA226_Driver =
{
	.WHT_Init              = WHT_INA226_Init,
    .WHT_Set_Work_Mode     = WHT_INA226_Set_Work_Mode,
	.WHT_Set_Calibration_Shunt_Gain = WHT_INA226_Set_CAL,
	.WHT_Set_Convert_Time  = WHT_INA226_Set_CNV_Time,
	.WHT_Set_Alert_Func    = WHT_INA226_Set_Alert_Func,
	.WHT_Set_Alert_Value   = WHT_INA226_Set_Alert_Value,
	.WHT_Get_Voltage       = WHT_INA226_Get_VBus_Voltage,
	.WHT_Get_Shunt_Voltage = WHT_INA226_Get_Shunt_Voltage,
	.WHT_Get_Current       = WHT_INA226_Get_IBus_Current,
	.WHT_Get_Power         = WHT_INA226_Get_WBus_Power,
	.WHT_Get_Alert_Flag    = WHT_INA226_Get_Alert_Flag,
    .WHT_Get_Default_Calibration_Shunt_Gain = WHT_INA226_Get_Default_CAL,
    .WHT_Scan_I2C_Slave_Count = WHT_INA226_Scan_I2C_Slave_Count,
};
